/*
1，重写一个组件系统依次调用Constructor（构造方法）-->createChildren()-->commitProperties()==>measure()==>updateDisplayList() ; 

a	Constructor				构造方法，初始化属性，默认值    最好在这个方法中设置。 
b	createChildren() 		创建子对象，在组件中添加子对象。然后用addChild方法添加子对象 
c	commitProperties 		用在处理属性值和更新。（多个属性值更新后统一处理入口和单值多次修改后处理入口） 
d	measure()				设置组件的默认大小（以便Flex布局管理器能正确知道该组件的大小，给其分配适当空间） 
e	updateDisplayList()		用来重绘组件，子对象布局逻辑等 

2,添加自定义组件实际上就是将一个个基本的组件的组合起来，这样的情况下就必须要重写createChildren() 和  updateDisplayList()方法 
当自定义组件要对属性的变化作出反应的时候必须要重写 commitProperties()方法（触发调用这个方法的是invalidateProperties） 
当自定义的组件和基类组件大小不一致的情况下就要调用measure 保证正确的大小显示。（调用invalidateSize方法） 
当组件需要调整子对象全局显示逻辑，重写updateDisplayList,调用 invalidateDisplayList 

commitProperties   measure 和 updateDisplayList 都有自己的用处 

在下面写个例子 一个button 和 TextArea 组合的自定义组件 
*/

package com.cn.wuxiong.ui
{
	import flash.events.Event;   
	import flash.text.TextLineMetrics;   
	
	import mx.controls.Button;   
	import mx.controls.TextArea;   
	import mx.core.UIComponent;   
	
	/**  
	 * 当子组件textArea中文件变化时，ModelText派发一个change事件  
	 * 当ModelText的text属性被设置时，派发一个textChange事件  
	 * 当改变Modeltext的textplacement属性后，会派发一个placementChanged事件   
	 * **/  
	[Event(name="change",type="flash.events.Event")]   
	[Event(name="textChanged",type="flash.events.Event")]   
	[Event(name="placementChanged",type="flash.events.Event")]   
	
	public class ModelText extends UIComponent   
	{   
		//两个私有变量（两个控件 一个文本域 和一个 按钮）
		private var text_mc:TextArea;
		private var mode_mc:Button;   
		
		private var bTextChanged:Boolean = false;   
		
		private var _text:String="ModelText";   

		public function ModelText(){//构造方法
			super();   
		}
		
		public function set text(t:String):void{   
			this._text =t;   
			bTextChanged = true;  
			
			/*标记组件，以便在稍后屏幕更新期间调用该组件的 commitProperties() 方法。 			
			 * Invalidation 是一个很有用的机制，可将组件更改延迟到稍后屏幕更新时进行处理，从而消除了重复的工作。
			 * 例如，要更改文本颜色和大小，如果在更改颜色后立即进行更新，然后在设置大小后再更新大小，就有些浪费。
			 * 同时更改两个属性后再使用新的大小和颜色一次性呈示文本，效率会更高。						
			 * 很少调用 Invalidation 方法。通常，在组件上设置属性会自动调用合适的 invalidation 方法。*/
			invalidateProperties();   
			dispatchEvent(new Event("textChanged"));//派发事件 
		}   
		
		
		[Bindable(event="textChanged")]   
		public function get text():String{
			return text_mc.text;   
		}   
		
		
		override protected function createChildren():void{   
			super.createChildren();
			if(!text_mc){   
				text_mc =new TextArea();   
				text_mc.explicitWidth =80;   
				text_mc.editable =false;   
				text_mc.addEventListener("change",handleChangeEvent);   
				addChild(text_mc);   
			}   
			
			if(!mode_mc){   
				mode_mc = new Button();   
				mode_mc.label ="mylabeljieji";   
				mode_mc.addEventListener("click",handleClickEvent);   
				addChild(mode_mc);   
			}   
		}   
		
		
		//处理有子组件派发的时间   
		private function handleChangeEvent(eventObj:Event):void{   
			dispatchEvent(new Event("change"));   
		}   
		
		private function handleClickEvent(eventObj:Event):void{   
			text_mc.editable = !text_mc.editable;   
		}   
		
		
		override protected function commitProperties():void{   
			super.commitProperties();   
			if(bTextChanged){
				bTextChanged =false;
				text_mc.text = _text;
				invalidateDisplayList();
			}   
		}   
		
		/**  
		 * 组建的默认宽度是文本宽度加上按钮的宽度  
		 * 组件的默认高度由按钮的高度决定  
		 */    
		override protected function measure():void{   
			super.measure();   
			var buttonWidth:Number = mode_mc.getExplicitOrMeasuredWidth();   
			var buttonHeight:Number =mode_mc.getExplicitOrMeasuredHeight();   
			
			//组件默认的最小宽度和默认宽度为textArea控件的measureedWidth宽度与buttonWidth之和   
			measuredWidth = measuredMinWidth =text_mc.measuredWidth+buttonWidth;   
			//组件的默认高度 和最小高度问textArea 和Button 中measuredHeight中的最大值加上10个像素的边框   
			measuredHeight = measuredMinHeight = Math.max(text_mc.measuredHeight,buttonHeight)+10;   
		}   
		
		
		private var _textPlacement:String="left";   
		
		public function set textPlacement(p:String):void{   
			this._textPlacement = p;   
			invalidateDisplayList();   
			dispatchEvent(new Event("placementChanged"));   
		}   
		
		[Bindable(event="placementChanged")]   
		public function get textPlacement():String{   
			return _textPlacement;   
		}   
		
		
		/**  
		 * Button控件的尺寸是Button上的label文本尺寸加上10像素的边框区域  
		 * textarea控件的尺寸是组件的剩余区域，TextArea的位置取决于textPlacement属性的设置  
		 * **/  
		override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void{   
			super.updateDisplayList(unscaledWidth,unscaledHeight);   
			//为左右边框各减去1像素 ， 为左右边白各减3像素   
			var usableWidth:Number=unscaledWidth -8;   
			//为上下边框各减去1像素 ， 为上下边白各减3像素   
			var usableHeight:Number = unscaledHeight -8;   
			
			//根据按钮上的文本计算按钮的尺寸   
			var lineMetrics:TextLineMetrics = measureText(mode_mc.label);   
			//按钮文本尺寸加上10像素作为按钮的尺寸   
			var buttonHeight:Number = lineMetrics.height+10;   
			var buttonWidth:Number = lineMetrics.width+10;   
			mode_mc.setActualSize(buttonWidth,buttonHeight);   
			
			//计算文本的尺寸，允许按钮和TextArea文本之间有5个像素的间隙   
			var textWidth:Number = usableWidth-buttonWidth-5;   
			var textHeight:Number = usableHeight;   
			text_mc.setActualSize(textWidth,textHeight);   
			
			//根据textPlacement的属性确定控件的位置   
			if(textPlacement == "left"){   
				text_mc.move(4,4);   
				mode_mc.move(4+textWidth+5,4);   
			}else{   
				mode_mc.move(4,4);   
				text_mc.move(4+buttonWidth+5,4);   
			}   
			
			graphics.lineStyle(1,0xffff00,1.0);   
			graphics.drawRect(0,0,unscaledWidth,unscaledHeight);   
		}   
	}   

}